package com.msg.server;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.msg.handler.CliMsgDispatcher;
import com.msg.service.LoginService;

import java.util.Arrays;

public class ServerHandler implements IoHandler {
	protected static final Logger log = LoggerFactory.getLogger(ServerHandler.class);
	// 超时时间(默认3分钟)
	private static long logOutTime = 180000L;

	public void messageReceived(IoSession session, Object msg) throws Exception {
		log.debug(session.getRemoteAddress() + "收到消息【" + ((session.containsAttribute("userId")) ? session.getAttribute("userId") : "") + "】:" + msg);
		if (StringUtils.isBlank(msg.toString()) || (msg.toString().length() > 4096) || (!msg.toString().startsWith("{")) || (!msg.toString().endsWith("}"))) {
			log.info("非法数据包：" + msg + " 服务器断开连接！");
			session.close(true);
			return;
		}
		try {
			if ((session.isClosing()) || (session.getRemoteAddress() == null)) {
				log.error("bad client:" + msg.toString());
				return;
			}

			JSONObject json = JSON.parseObject(msg.toString());
			if ((!json.containsKey("msgId")) || (!NumberUtils.isNumber(json.getString("msgId")))) {
				log.info("未知数据包：" + msg);
				session.close(true);
				return;
			}
			/****************** 心跳包 ********************************************/
			int msgID = json.getIntValue("msgId");
			if (msgID == 0) {
					return;
			}
			if (msgID == 201) {
				if (!json.containsKey("appId")) {
					log.debug("未知数据包：" + msg);
					session.close(true);
					return;
				}
				if (!json.containsKey("data")) {
					log.debug("未知数据包：" + msg);
					session.close(true);
					return;
				}
				if (!json.getJSONObject("data").containsKey("userId")) {
					log.debug("未知数据包：" + msg);
					session.close(true);
					return;
				}
				String userId = json.getJSONObject("data").getString("userId");
				CliMsgDispatcher.receiveMsg(session, userId, msgID, json);
			} else if (!session.containsAttribute("userId")) {
				session.close(true);
			} else {
				String userId = String.valueOf(session.getAttribute("userId"));
				CliMsgDispatcher.receiveMsg(session, userId, msgID, json);
			}
		} catch (Exception e) {
			log.debug("未知数据包异常：" + msg, e);
			session.close(true);
		}
	}

	public void messageSent(IoSession arg0, Object arg1) throws Exception {
	}

	/**
	 * session关闭时调用
	 */
	public void sessionClosed(IoSession session) throws Exception {
		long logoutTime = System.currentTimeMillis();
		if (session.containsAttribute("userId")) {
			Object userId = session.getAttribute("userId");
			log.debug("SessionId:" + session.getId() + "; 用户[" + userId + "]下线，下线时间:" + logoutTime + "  上线时间:" + session.getCreationTime() + "  在线时长[" + (logoutTime - session.getCreationTime()) + "]");
			Object appId = session.getAttribute("appId");
			LoginService.userLogout(appId.toString(), session, String.valueOf(userId), logoutTime);
		}
	}

	/**
	 * 会话创建
	 */
	public void sessionCreated(IoSession session) throws Exception {
		log.debug("当前会话创建成功,sessionAdd:[" + session.getRemoteAddress() + "]，sessionId: " + session.getId());
	}

	/**
	 * session轮询操作3分钟视为超时
	 */
	public void sessionIdle(IoSession session, IdleStatus arg1) throws Exception {
		if ((System.currentTimeMillis() - session.getLastIoTime()) > logOutTime) {
			log.debug("User[" + session.getAttribute("userId") + "] 连接超时,自动关闭session. session id:" + session.getId() + " session info:" + session);
			session.close(true);
		}
	}

	public void exceptionCaught(IoSession session, Throwable t) throws Exception {
		log.debug("[" + session.getAttribute("userId") + "]消息异常,断开连接" + Arrays.toString(t.getStackTrace()), t);
		session.close(true);
	}

	public void sessionOpened(IoSession session) throws Exception {
	}

}
